package org.txazo.music.commons.mp3;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;

/**
 * MP3解析
 * 
 * @author Tu XiaoZhou
 * @since 2013-04-12
 * 
 */
public class MP3Reader {

	/** ID3v2标识 */
	private static final String MP3_ID3 = "ID3";
	/** 歌名标识 */
	private static final String MP3_TIT2 = "TIT2";
	/** 歌手标识 */
	private static final String MP3_TPE1 = "TPE1";
	/** 专辑标识 */
	private static final String MP3_TALB = "TALB";
	/** 年份标识 */
	private static final String MP3_TYER = "TYER";
	/** 图片标识 */
	private static final String MP3_APIC = "APIC";

	/** ID3v2标签帧标识 */
	private static final String[] MP3_TAGS = new String[] { "AENC", "APIC",
			"COMM", "COMR", "ENCR", "EQUA", "ETCO", "GEOB", "GRID", "IPLS",
			"LINK", "MCDI", "MLLT", "OWNE", "PRIV", "PCNT", "POPM", "POSS",
			"RBUF", "RVAD", "RVRB", "SYLT", "SYTC", "TALB", "TBPM", "TCOM",
			"TCON", "TCOP", "TDAT", "TDLY", "TENC", "TEXT", "TFLT", "TIME",
			"TIT1", "TIT2", "TIT3", "TKEY", "TLAN", "TLEN", "TMED", "TOAL",
			"TOFN", "TOLY", "TOPE", "TORY", "TOWN", "TPE1", "TPE2", "TPE3",
			"TPE4", "TPOS", "TPUB", "TRCK", "TRDA", "TRSN", "TRSO", "TSIZ",
			"TSRC", "TSSE", "TYER", "TXXX", "UFID", "USER", "USLT", "WCOM",
			"WCOP", "WOAF", "WOAR", "WOAS", "WORS", "WPAY", "WPUB", "WXXX" };

	/** MP3文件 */
	private String file;
	/** 标签头 */
	private byte[] head;
	/** 标签帧 */
	private byte[] frame;

	public MP3Reader(String file) {
		this.file = file;
		head = load(0, 10);
	}

	public byte[] load(int index, int length) {
		byte[] data = new byte[length];
		try (FileInputStream fis = new FileInputStream(file)) {
			fis.skip(index);
			fis.read(data);
		} catch (IOException e) {
			e.printStackTrace();
		}
		return data;
	}

	public MP3 getMP3() {
		MP3 mp3 = new MP3();

		if (isID3v2()) {
			frame = load(10, getFrameSize());

			int index = 0;
			boolean flag = true;
			while (flag) {
				String tag = convertToString(frame, index, 4, "GBK");
				if (isID3v2Tag(tag)) {
					index += 4;
					int size = getFrameContentSize(index);
					index += 6;

					if (tag.equals(MP3_TIT2)) {
						mp3.setTitle(getFrameContent(index, size));
					} else if (tag.equals(MP3_TPE1)) {
						mp3.setArtist(getFrameContent(index, size));
					} else if (tag.equals(MP3_TALB)) {
						mp3.setAlbum(getFrameContent(index, size));
					} else if (tag.equals(MP3_TYER)) {
						mp3.setYear(getFrameContent(index, size));
					} else if (tag.equals(MP3_APIC)) {
						int length = index + size;
						for (int i = index; i < length; i++) {
							if (frame[i] == -1 && frame[i + 1] == -40) {
								byte[] data = new byte[size + index - i];
								System.arraycopy(frame, i, data, 0, size
										+ index - i);
								MP3ImageWriter.writeImage(data, getFileName());
								break;
							}
						}
					}

					index += size;
				} else {
					flag = false;
				}
			}
		}

		return mp3;
	}

	public String getFrameContent(int index, int size) {
		int encoding = frame[index];
		if (encoding == 0 || encoding == 3) {
			if (size != 1) {
				return convertToString(frame, index + 1, size - 1, "GBK");
			}
			return null;
		}
		return convertToString(frame, index + 1, size - 1, "UTF-16");
	}

	public int getFrameSize() {
		return (int) (head[6] & 0x7F) << 21 | (int) (head[7] & 0x7F) << 14
				| (int) (head[8] & 0x7F) << 7 | (int) (head[9] & 0x7F);
	}

	public int getFrameContentSize(int index) {
		return (int) (frame[index] & 0x7F) << 24
				| (int) (frame[index + 1] & 0x7F) << 16
				| (int) (frame[index + 2] & 0x7F) << 8
				| (int) (frame[index + 3] & 0x7F);
	}

	public boolean isID3v2() {
		return MP3_ID3.equals(convertToString(head, 0, 3, "GBK"));
	}

	public boolean isID3v2Tag(String str) {
		for (String tag : MP3_TAGS) {
			if (str.equals(tag)) {
				return true;
			}
		}
		return false;
	}

	/**
	 * 字节数组转换为字符串
	 */
	public static String convertToString(byte[] data, int offset, int length,
			String charset) {
		String str = null;
		try {
			if (data.length >= offset + length) {
				str = new String(data, offset, length, charset);
			} else {
				str = new String(data, offset, data.length - offset, charset);
			}
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return str;
	}

	/**
	 * 获取文件名
	 */
	public String getFileName() {
		file = file.replace('\\', '/');
		String[] data = file.split("/");
		return data[data.length - 1].replace(".mp3", "");
	}

	public static void main(String[] args) {
		File file = new File("D:/MyMusic/MyMusic");
		File[] childs = file.listFiles();
		File child = null;
		int count = 0;
		int length = childs.length;
		for (int i = 0; i < length; i++) {
			child = childs[i];
			if (child.isFile() && child.getName().endsWith(MP3Util.SUFFIX_MP3)) {
				MP3Reader reader = new MP3Reader(child.getAbsolutePath());
				System.out.println(child.getAbsolutePath());
				MP3 mp3 = reader.getMP3();
				System.out.print(count++ + ">>>");
				System.out.println(mp3);
				System.out.println(reader.getFrameSize());
			}
		}
	}

}
